EthernetService
本篇内容基于Android 6.0.1,涉及到的framework类
frameworks\opt\net\ethernet\java\com\android\server\ethernet\EthernetService.java
frameworks\opt\net\ethernet\java\com\android\server\ethernet\EthernetServiceImpl.java
\frameworks\base\core\java\android\net\EthernetManager.java
\frameworks\base\core\java\android\net\IEthernetManager.aidl
\frameworks\base\core\java\android\net\IpConfiguration.java
/frameworks/base/services/core/java/com/android/server/SystemServiceManager.java
以太网中在一般的Android Phone中是不存在的,不过在一些智能硬件中带有以太网的模块,因此需要有一系列的
接口来访问以太网的状态信息。比如当前的以太网的模式和连接状态等
但是,EthernetService的服务接口只是在framework层可用,并没有开放给用户。实际上看过源码可以看到一些@hide标记的
api和类,这也说明它们对用户层不可用。那么我们如何去获取以太网的状态信息呢?
本篇将介绍如何在framework中EthernetService中添加这样的接口来供用户访问,这里以添加获取当前的以太网的模式为例,我们知道Android
中Service提供服务是通过Binder来支持的,而AIDL为跨进程访问提供用户访问的接口,而以太网服务的接口是通过IEthernetManager.aidl来定义的
在SystemService启动时会去注册一系列的Service到ServiceManager中去,这里我们先看EthernetService是如何启动的。
1 | public final class SystemServer { |
在SystemService中会去通过一个SystemServiceManager的startService方法来启动,从参数大概可以猜出来它会通过反射去创建Service实例。
1 |
|
通过反射创建EthernetService实例,并添加到列表中管理起来。随后调用onStart启动它。我们先看看EthernetService,它有可能就是我们的要找的Binder Server。
1 | package com.android.server.ethernet; |
EthernetService的实现很简单,它并不是真正的Binder Server,它的任务很简单是就是去注册一个服务EthernetServiceImpl,注册到哪去了呢?
这还用问?当然是ServiceManager中,这里EthernetService继承自SystemService,publishBinderService正是在它里面实现的,它将服务实体
注册到ServiceManager中去。那么毋庸置疑,这里的EthernetServiceImpl就是Binder Server了。
1 | /** |
从其实现来看它的确是,因为它继承了IEthernetManager.Stub,从而有了跨进程的能力。我们看看它提供了的接口定义
1 | /** {@hide} */ |
看过context的同学可能知道ContextImpl在创建的时候会去注册一些服务管理对象,这些都是被添加到静态实例中,以供多个context实例共享使用,这也是我们为什么
能够通过Context.getSystemService获取服务的原因,而EthernetService是通过EthernetManager来管理的。
1 | registerService(Context.ETHERNET_SERVICE, EthernetManager.class, |
那么我们为什么不能用Context获取getSystemService来获取EthernetService的管理者从而访问其服务接口呢?
原因是Context中不允许我们这么做,对ETHERNET_SERVICE使用了@hide,这样我们就不能取到ETHERNET_SERVICE的服务,
如果我们在代码中直接引用EthernetManager也会报错,因为EthernetManager对上层是不可见的。
public abstract class Context {
1 | 2832 /** |
这可如何是好?有一个办法,那就是通过反射,通过反射可以取到service的实例,从而进行访问service这些隐藏的api,当然这也有很大的局限性,
而且会带来可能存在的风险,比如当系统版本变动后就会带来不可预知的问题。但对于特定的硬件产品(系统确定且不会再变更)来说,这也算是一种有效的方法。为了避免可能存在的问题,我们最好添加一些先验条件来使用。
1 | private static int getEthernetMode(Context context) |
###编译
编译 framework.jar
在上述的内容中我们添加了getEthernetMode以获取以太网的模式,即是动态还是静态的。我们的改动主要在aidl和service中,因此需要编译相关的模块。
首先执行
1 | source ./build/envsetup.sh |
编译得到 framework.jar ,它的位置在
out\target\product\xxx\system\framework\framework.jar
编译完成后我们也可以看到生成的IEthernetManager.java了,它的位置在
\out\target\common\obj\JAVA_LIBRARIES\framework_intermediates\src\core\java\android\net\IEthernetManager.java
IEthernetManager.java为IEthernetManager.aidl对应的java文件,打开它就可以看到我们定义的接口
编译ethernet-service.jar
1 | cd frameworks/opt/net/ethernet/ |
编译得到ethernet-service.jar ,它的位置在
out\target\product\xxx\system\framework\ethernet-service.jar
最后将framework.jar和ethernet-service.jar push到system/framework/目录下重启后就可以在客户程序中通过getEthernetMode使用我们提供的接口服务了。
完。